package thread;

import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: wx
 * Date: 2024-01-03
 * Time: 19:04
 */
public class ThreadDemo22 {
    private volatile static int flag1 = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(() ->{
            while(flag1 == 0) {

                System.out.println("T1 线程结束");
            }
        });
        Thread t2 = new Thread(() ->{
            System.out.println("请输入 flag 的值: ");
            Scanner scanner = new Scanner(System.in);
            flag = scanner.nextInt();

        });
        t1.start();
        t2.start();

    }
    private static int flag = 0;

    public static void main2(String[] args) {
        Thread t1 = new Thread(() ->{
            while(flag == 0){
                //核心指令两条
                //1.load 读取内存中 flag 的值到cpu寄存器里
                //2.拿着寄存器的值和 0 进行比较(条件跳转指令)
                //由于上述循环中,循环执行速度非常快 反复执行 1,2
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("T1 线程结束");
        });
        Thread t2 = new Thread(() ->{
            System.out.println("请输入 flag 的值: ");
            Scanner scanner = new Scanner(System.in);
            flag = scanner.nextInt();

        });
        t1.start();
        t2.start();

    }

    public static void main1(String[] args) {
        Thread t1 = new Thread(() ->{
           while(flag == 0){
                                //核心指令两条                                       //这个执行过程中,有两个关键要点:
                                //1.load 读取内存中 flag 的值到cpu寄存器里               //1.load操作执行的结果,每次都是一样的                                  // 频繁执行 load 和条件跳转 load 开销大,并且load的结果又没有变化
                                //2.拿着寄存器的值和 0 进行比较(条件跳转指令)               //要想输入,过几秒才能输入,在这几秒之内已经执行了不知多少次执行了             // (真正的变化是好几秒之后的事情)
                            //由于上述循环中,循环执行速度非常快 反复执行 1,2                //2.load 操作的开销远远超过 条件跳转                                  //  此时 JVM 就产生怀疑,怀疑 load 操作是否真的有必要存在?
           }                                                                        //  访问寄存器的操作速度,远远超过访问内存                              //   因此,JVM 就可能进行做出代码优化,把上述 load操作,给优化掉
            System.out.println("T1 线程结束");                                                                                                       //   (只有前几次进行 load 操作,后续发现,load 反正都一样,静态分析代码,也没看到哪里改了
        });                                                                                                                                        //    因此就直接激进的把 load操作,给干掉了)    干掉之后,就相当于不再重复读内存,直接使用寄存器中之前"缓存的值" 大幅度的提高了循环的执行速度
        Thread t2 = new Thread(() ->{
            System.out.println("请输入 flag 的值: ");
            Scanner scanner = new Scanner(System.in);
            flag = scanner.nextInt();

        });
        t1.start();
        t2.start();
        //这个代码中,预期通过 t2 线程输入的整数
        //只要输入的不为 0,就可以使t1线程结束
        //实际输入一个非0的值,并没有结束
        /**
         * 上述问题和内存可见性问题有关
        就相当于 t2 修改了内存
        但是 t1 没有看到这个内存的变化
        就称为内存可见性问题
         * 内存可见性问题高度依赖编译器优化的问题,啥时候出发这个问题,啥事不触发这个问题,不好说
         * java 中提供了 volatile 这个关键字就可以使上述优化被强制关闭,可以确保每次循环条件都会重新从内存中读取数据
         *               就是指强制读取内存(开销大了,效率低了,数据的准确性/逻辑的正确性,提高了)
         *               核心功能
         *               1.保证内存可见性
         *               2.禁止指令重排序
         */

        /*
        JMM(Java Memory Model)
        咱们上面的表示:
        在上述代码中,编译器发现,每次循环都要读取内存,开销太大
        于是就把读取内存优化成读取寄存器操作,提高效率

        在 JMM 模型下表述:
        在上述代码中,编译器发现,每次循环都要读取"主内存"
        就会把数据从"主内存"中复制到工作内存中,后续每次都是读取"工作内存"
        */
    }
}
